package com.lie.prepare.multi_thread.specialLock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

/**
 * Created by lie on 2018/4/10.
 * 模拟对象池
 * @see Semaphore 是一种特殊的锁，支持多个任务同时获取锁（可以理解成发放一定数量的许可证）
 */
public class MyPool<T> {
    private int size;
    private List<T> items = new ArrayList<T>();
    private volatile boolean[] checkedOut;
    private Semaphore available;

    public MyPool(Class<T> classObject, int size) {
        this.size = size;
        checkedOut = new boolean[size];
        //在这里定义了许可证的数量
        available = new Semaphore(size, true);
        for (int i = 0; i < size; i++) {
            try {
                items.add(classObject.newInstance());
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //对外提供实例
    public T checkOut() throws InterruptedException {
        available.acquire();//如果没有更多许可证了，则这里会阻塞
        return getItem();
    }

    //使用完实例，则丢进来回收
    //假如被签入的对象有效，则会像信号量返回一个许可证
    public void checkIn(T x){
        if (releaseItem(x))
            available.release();
    }

    private synchronized boolean releaseItem(T x) {
        int index = items.indexOf(x);
        if (index == -1) return false;

        if (checkedOut[index]){
            checkedOut[index] = false;
            return true;
        }
        return false;
    }

    private synchronized T getItem(){
        for (int i = 0; i < size; i++) {
            if (! checkedOut[i]){
                checkedOut[i] = true;
                return items.get(i);
            }
        }
        return null;
    }
}
